#include "zrpc/http/http_context.h"

#include "zrpc/base/buffer.h"
namespace zrpc {
bool HttpContext::ProcessResponseLine(const char *begin, const char *end) {
  bool succeed = false;
  const char *start = begin;
  const char *space = std::find(start, end, ' ');
  if (space != end) {
    succeed = space - start == 8 && std::equal(start, space - 1, "HTTP/1.");
    if (succeed) {
      if (*(space - 1) == '1') {
      } else if (*(space - 1) == '0') {
      } else {
        succeed = false;
      }
    }

    start = space + 1;
    space = std::find(start, end, ' ');
    if (space != end) {
      response_.SetStatusCode(start, space);
      start = space + 1;
      if (start != end) {
        response_.SetStatusMessage(start, end);
      }
    }
  }
  return succeed;
}

bool HttpContext::ProcessRequestLine(const char *begin, const char *end) {
  bool succeed = false;
  const char *start = begin;
  const char *space = std::find(start, end, ' ');
  if (space != end && request_.SetMethod(start, space)) {
    start = space + 1;
    space = std::find(start, end, ' ');
    if (space != end) {
      const char *question = std::find(start, space, '?');
      if (question != space) {
        request_.SetPath(start, question);
        request_.SetQuery(question + 1, space);
      } else {
        request_.SetPath(start, space);
      }

      start = space + 1;
      succeed = end - start == 8 && std::equal(start, end - 1, "HTTP/1.");
      if (succeed) {
        if (*(end - 1) == '1') {
          request_.SetVersion(HttpRequest::kHttp11);
        } else if (*(end - 1) == '0') {
          request_.SetVersion(HttpRequest::kHttp10);
        } else {
          succeed = false;
        }
      }
    }
  }
  return succeed;
}

bool HttpContext::ParseResponse(Buffer *buf) {
  bool ok = true;
  bool has_more = true;
  while (has_more) {
    if (state_ == kExpectRequestLine) {
      const char *crlf = buf->FindCRLF();
      if (crlf) {
        ok = ProcessResponseLine(buf->Peek(), crlf);
        if (ok) {
          buf->RetrieveUntil(crlf + 2);
          state_ = kExpectHeaders;
        } else {
          has_more = false;
        }
      } else {
        has_more = false;
      }
    } else if (state_ == kExpectHeaders) {
      const char *crlf = buf->FindCRLF();
      if (crlf) {
        const char *colon = std::find(buf->Peek(), crlf, ':');
        if (colon != crlf) {
          response_.AddHeader(buf->Peek(), colon, crlf);
        } else {
          state_ = kExpectBody;
        }
        buf->RetrieveUntil(crlf + 2);
      } else {
        has_more = false;
      }
    } else if (state_ == kExpectBody) {
      has_more = false;
      if (buf->ReadableBytes() == response_.GetBodySize()) {
        response_.SetBody(std::string(buf->Peek(), buf->ReadableBytes()));
        buf->RetrieveAll();
        state_ = kGotAll;
      } else {
        return false;
      }
    }
  }
  return ok;
}

bool HttpContext::ParseRequest(Buffer *buf) {
  bool ok = true;
  bool has_more = true;
  while (has_more) {
    if (state_ == kExpectRequestLine) {
      const char *crlf = buf->FindCRLF();
      if (crlf) {
        ok = ProcessRequestLine(buf->Peek(), crlf);
        if (ok) {
          buf->RetrieveUntil(crlf + 2);
          state_ = kExpectHeaders;
        } else {
          has_more = false;
        }
      } else {
        has_more = false;
      }
    } else if (state_ == kExpectHeaders) {
      const char *crlf = buf->FindCRLF();
      if (crlf) {
        const char *colon = std::find(buf->Peek(), crlf, ':');
        if (colon != crlf) {
          request_.AddHeader(buf->Peek(), colon, crlf);
        } else {
          state_ = kGotAll;
          has_more = false;
        }
        buf->RetrieveUntil(crlf + 2);
      } else {
        has_more = false;
      }
    } else {
      has_more = false;
    }
  }
  return ok;
}
}  // namespace zrpc
